package com.rk.pethome.user.Service.Impl;
import com.rk.pethome.basic.constant.VerificationCodestant;
import com.rk.pethome.basic.service.impl.BaseServiceImpl;
import com.rk.pethome.basic.util.*;
import com.rk.pethome.user.Service.IUserService;
import com.rk.pethome.user.Vo.UserDot;
import com.rk.pethome.user.constant.UserConstant;
import com.rk.pethome.user.domain.User;
import com.rk.pethome.user.mapper.UserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class IUserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SendMailUtil mailUtil;


    /**
     * 通过邮箱进行注册
     * @param userDot
     * @return
     */
    @Override
    public AjaxResult registerEmail(UserDot userDot){
        try {
            //判断密码是否输入
            if(StringUtils.isBlank(userDot.getPassword())||StringUtils.isBlank(userDot.getConfirmPassword()))
                return new AjaxResult(false,"请输入密码");
            //如果两次面不相等
            if(!userDot.getPassword().equals(userDot.getConfirmPassword()))
                return new AjaxResult(false,"两次密码不一致");

            //校验邮箱是否存在
            AjaxResult ajaxResult = checkEmail(userDot.getEmail());
            if(ajaxResult!=null)//不等于空，说明存在
                return ajaxResult;

            //保存对象
            User user=new User();
            user.setUsername(userDot.getEmail());
            user.setEmail(userDot.getEmail());
            user.setState(UserConstant.DISABLED);//默认未激活

            //给用户密码进行盐值加密
            //设置盐值
            String Salt=StrUtils.getComplexRandomString(10);
            user.setSalt(Salt);
            //通过盐值加密    密码加盐值
            user.setPassword(MD5Utils.encrypByMd5(userDot.getPassword()+user.getSalt()));
            //保存用户
            userMapper.saveUser(user);
            //给刚注册好的用户发送邮件
            testTemplateMail(user.getEmail());
            return new AjaxResult(true,"邮件已发送至邮箱，请在10分钟内完成激活操作!");
        } catch (Exception e){
            e.printStackTrace();
            return new AjaxResult(false,"注册失败!");
        }
    }

    /**
     * 发送邮件
     * @param receiver 收件人
     */
    @Async
    public void testTemplateMail(String receiver){
        //发送邮件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        String subject = "宠物之家--用户注册";
        String emailTemplate = "registerTemplate";
        //获取激活码
        String code = StrUtils.getRandomString(5);
        //将激活码存入redis服务器
        //设置有效期10分钟  key值为:Action+邮箱 value值为:验证码
        RedisUtils.INSTANCE.set(VerificationCodestant.EMAIL_REG+receiver,code,10*60);
        System.out.println("key:"+VerificationCodestant.EMAIL_REG+receiver+"   value:"+code);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("email", receiver);
        dataMap.put("code", code);
        dataMap.put("createTime", sdf.format(new Date()));
        try {
            mailUtil.sendTemplateMail(receiver, subject, emailTemplate, dataMap);
            System.out.println("发送完成");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }


    /**
     * 校验邮箱是否存在
     * @param email
     */
    @Override
    public AjaxResult checkEmail(String email){
        //通过用户名用户对象
        User user = userMapper.loadByUsername(email);
        //如果查询不为空 邮箱已被注册
        if(user!=null)
        {
            return new AjaxResult(false,"该邮箱已被注册");
        }
        return new AjaxResult();
    }

    /**
     * 校验手机号码是否存在
     *
     * @param phone
     */
    @Override
    public void checkPhone(String phone) {
        //通过手机号码查询用户对象
        User user = userMapper.loadByPhone(phone);
        //如果查询不为空 手机号已被注册
        if(user!=null)
        {
            throw  new RuntimeException("手机号码已被注册!!");
        }
    }

    /**
     * 发送验证码
     * @param phone
     * 	发送验证码逻辑:
     * 		1、随机产生四位验证码==有效期10分钟
     * 		2、一分钟以内如果是同一个手机号发送了多次验证码，我就要提示用户，不能连续发送。(虽然点击发送验证码按钮后，该按钮会被禁用一分钟，但是可以刷新页面再次点击发送验证码)
     * 		3、如果验证码超过了一分钟，我又点击了一次发送请求，这时候我用的应该是之前的验证码
     * 		4、如果验证码失效了，应该产生新的验证码
     */
    @Override
    public void sendMobileCodebyPhone(String phone) {
        //产生随机4位验证码
        String code = StrUtils.getRandomString(4);
        //通过key获取Redis中对应的值 格式:验证码:时间戳
        String value = RedisUtils.INSTANCE.get(VerificationCodestant.USER_REG + phone);
        if(StringUtils.isNotBlank(value)){//判断是否为空 如果不为空，就代表验证码没有过期
            //截取字符串 获取时间错
            Long beginTime = Long.valueOf(value.split(":")[1]);
            //如果第二次时间减去上一次时间小于1分钟，就证明一分钟以内发送了多次请求
            if(System.currentTimeMillis()-beginTime<60*1000){
                throw new RuntimeException("1分钟内请不要发送多次请求");
            }
            //超过1分钟，但是验证码还没有过期，还是用之前的验证码
            code=value.split(":")[0];
        }
        //设置有效期10分钟  key值为:USER_REG加手机号  区分一下，这是用户注册的验证码，找回密码等其他需要验证码的操作key必须不同，避免重复
        RedisUtils.INSTANCE.set(VerificationCodestant.USER_REG+phone,code+":"+System.currentTimeMillis(),10*60);
        //用打印语句模拟发送短信
        //System.out.println("尊敬的客户，您的验证码是:"+code+",请在10分钟内完成注册操作!");
        String text="尊敬的客户，您的验证码是:"+code+",请在10分钟内完成注册操作!";
        //SendMsgUtil.sendCode(phone,text);
        System.out.println(text);
    }


    /**
     * 通过手机号注册
     * @param userDot
     * @return
     */
    @Override
    @Transactional
    public AjaxResult registerPhone(UserDot userDot){
        try {
            AjaxResult ajaxResult = verifyPhone(userDot);
            if(!ajaxResult.getSuccess())//校验未通过
                return ajaxResult;

            User reguser = loadByUsername(userDot.getPhone());
            if(reguser!=null)
                return new AjaxResult(false,"该手机号已被注册!!");

            //校验通过  保存用户
            System.out.println("校验通过");
            User user=new User();
            user.setUsername(userDot.getPhone());
            user.setPhone(userDot.getPhone());
            user.setState(UserConstant.ACTIVATION);//手机验证通过后已激活1
            //给用户密码进行盐值加密
            String salt=StrUtils.getComplexRandomString(10);
            //设置盐值
            user.setSalt(salt);
            //进行盐值加密
            user.setPassword(MD5Utils.encrypByMd5(userDot.getPassword()+user.getSalt()));
            //保存用户
            userMapper.saveUser(user);
            return new AjaxResult();
        } catch (Exception e) {
            e.printStackTrace();
            return new AjaxResult(false,e.getMessage());
        }
    }

    /**
     * 校验输入
     * @param userDot
     * @return
     */
    @Override
    public AjaxResult verifyPhone(UserDot userDot) {
        //手机认证 null和是否存在
        if (StringUtils.isBlank(userDot.getPhone())||StringUtils.isBlank(userDot.getPassword()) || StringUtils.isBlank(userDot.getConfirmPassword()))
            return new AjaxResult(false,"请输入手机号或者密码!!");

        //校验密码和确认密码
        if(!userDot.getPassword().equals(userDot.getConfirmPassword()))
            return new AjaxResult(false,"两次密码不一致");

        //校验验证码
        if(StringUtils.isBlank(userDot.getCode()))
            return new AjaxResult(false,"请输入验证码!!");
        else{//验证码输入
            //获取手机短信验证码
            String codeRight = RedisUtils.INSTANCE.get(VerificationCodestant.USER_REG+ userDot.getPhone()).split(":")[0];
            System.out.println("后台验证码USER_REG:"+userDot.getPhone()+"::"+codeRight);
            //获取用户输入的验证码
            String codeInput = userDot.getCode();
            if(!codeRight.equals(codeInput))
                return new AjaxResult(false,"验证码错误");
        }
        return new AjaxResult();
    }


    /**
     * 通过邮箱或者手机号的的登录
     * @param user
     * @return
     */
    @Override
    public AjaxResult login(User user){
        if (StringUtils.isBlank(user.getUsername())||StringUtils.isBlank(user.getPassword()))
            return new AjaxResult(false,"请输入用户名和密码!!");
        //通过用户名查询用户 查询到之后获取用户盐值
        User byusername = userMapper.loadByUsername(user.getUsername());
        if(byusername==null)
            return new AjaxResult(false,"用户名错误!!");

        //获取通过md5盐值加密的密码
        String s = MD5Utils.encrypByMd5(user.getPassword()+byusername.getSalt());
        user.setPassword(s);
        User loginu = userMapper.login(user);
        if(loginu==null)
            return new AjaxResult(false,"密码错误!!");
        if(loginu.getState()==UserConstant.DISABLED)//用户未激活
            return new AjaxResult(false,"用户未激活，请激活用户后登录!!");
        return  new AjaxResult();
    }

    /**
     * 用户激活
     *
     * @param email 邮箱
     * @param code  激活码
     * @return
     */
    @Override
    public AjaxResult activation(String email, String code) {
        //判断输入是否为空
        if(StringUtils.isBlank(email)||StringUtils.isBlank(code)){
            return new AjaxResult(false,"请输入邮箱和激活码!!");
        }
        //校验激活码是否正常
        //从redis服务器中获取code值，如果code值为空，说明激活码错误或者已过期!
        String s = RedisUtils.INSTANCE.get(VerificationCodestant.EMAIL_REG + email);//redis服务器上获取的激活码
        System.out.println("redis服务器上获取的激活码为:"+s);
        if(s==null)
            return new AjaxResult(false,"邮箱错误或者激活码已过期!!");
        //激活码是否正确
        if(!code.equals(s))//不正确
        {
            return new AjaxResult(false,"激活码错误!!");
        }

        //激活后从redis服务器上移除
        RedisUtils.INSTANCE.del(VerificationCodestant.EMAIL_REG + email);

        //修改用户状态为1    说明用户已经激活
        userMapper.updateState(email);

        return new AjaxResult();
    }

    /**
     * 通过用户名 邮箱 手机号查找用户
     * @param username
     *
     */
    @Override
    public User loadByUsername(String username) {
        return userMapper.loadByUsername(username);
    }
}
